<html>
<head><meta charset="utf-8"><title>Trying to understand some weird misoptimization · general · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/index.html">general</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Trying.20to.20understand.20some.20weird.20misoptimization.html">Trying to understand some weird misoptimization</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="224394819"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Trying%20to%20understand%20some%20weird%20misoptimization/near/224394819" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Elichai Turkel <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Trying.20to.20understand.20some.20weird.20misoptimization.html#224394819">(Jan 28 2021 at 21:25)</a>:</h4>
<p>In this code snippet: <a href="https://godbolt.org/z/Ge868W">https://godbolt.org/z/Ge868W</a><br>
I'm trying to understand why <code>mem_swap</code> has worse assembly where <code>mem_replace</code> is calling <code>std::mem::replace</code> which internally calls <code>std::mem:swap</code> itself! so <code>mem_swap</code> should be optimized the same as <code>mem::replace</code> is! (maybe even better because it's easier to see that <code>src</code> is discarded(after inlining once) while in <code>mem_replace</code> it can only know it after inlining twice).<br>
what am I missing here?<br>
The code in godbolt:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">struct</span> <span class="nc">A</span><span class="p">([</span><span class="kt">u8</span><span class="p">;</span><span class="w"> </span><span class="mi">32</span><span class="p">]);</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">direct_replace</span><span class="p">(</span><span class="n">a</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="nc">A</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="o">*</span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">mem_replace</span><span class="p">(</span><span class="n">a</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="nc">A</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span>::<span class="n">mem</span>::<span class="n">replace</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">mem_swap</span><span class="p">(</span><span class="n">a</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">b</span>: <span class="nc">A</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">std</span>::<span class="n">mem</span>::<span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">b</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="224395282"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Trying%20to%20understand%20some%20weird%20misoptimization/near/224395282" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Lukas Wirth <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Trying.20to.20understand.20some.20weird.20misoptimization.html#224395282">(Jan 28 2021 at 21:29)</a>:</h4>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">mem_swap</span><span class="p">(</span><span class="n">a</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="nc">A</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="n">std</span>::<span class="n">mem</span>::<span class="n">swap</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">b</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>interestingly enough, this snippet generates the same assembly that <code>mem_replace</code> generates</p>



<a name="224448873"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Trying%20to%20understand%20some%20weird%20misoptimization/near/224448873" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Giacomo Stevanato <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Trying.20to.20understand.20some.20weird.20misoptimization.html#224448873">(Jan 29 2021 at 09:48)</a>:</h4>
<p>I guess this has to do with the function parameters ABI. <code>b</code> is passed as a pointer and <code>mem_swap</code> (only that function) writes to it, which results in LLVM not eliding that write because the caller may observe it, even though the rust compiler will never generate a program that reads it since <code>b</code> is considered moved after that (at least in a sound program). Is this a problem? I guess no. In an actual program LLVM probably has informations about the caller (after all <code>mem_swap</code> will probably be inlined) and in that case it should be able to optimize it. For example even the following is optimized the same as <code>mem_replace</code>:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">calls_mem_swap</span><span class="p">(</span><span class="n">a</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">A</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="nc">A</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">mem_swap</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>